/**
 * @file Testing.h
 * @author  Johan Waldeback <openfms@waldeback.se>
 *
 * @section DESCRIPTION
 *
 * MACROS FOR TESTING
 *   - Compile the file with -DMAKE_TEST and a test program will be created
 *  Note: the file should not contain a main() function , or the main should
 *         be hidden between #ifndef MAKE_TEST ... #endif
 *
 * Copyright (C) 2010 Johan Waldeback
 *  
 * This file is part of the OpenFMS project (http://www.openfms-project.org)
 * 
 * OpenFMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * USAGE:
 * 
 * BEGIN_TESTING()
 *   UNITTEST_FLOAT_EQUALS( 1.1f, addFloats(0.5f, 0.6f) )
 *   UNITTEST_FLOAT_EQUALS( 3.1f, addFloats(1.5f, 3.6f) )
 *   UNITTEST_BOOL_EQUALS( true, fnCompareEquals(4,4) )
 *   UNITTEST_BOOL_EQUALS( false, fnCompareEquals(4,5) )
 *   ...
 * END_TESTING()
 *
 * @section LICENSE
 *
 * Copyright (C) 2010 Johan Waldeback
 *
 * This file is part of the OpenFMS project (http://www.openfms-project.org)
 * 
 * OpenFMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#ifndef __TESTING_H__
#define __TESTING_H__

#ifdef MAKE_TEST
#include <iostream>
#include <cmath>
#endif // MAKE_TEST


/**
 * Test if two variables have the same value
 * 
 */
#ifdef MAKE_TEST
#define UNITTEST_EQUALS( _TYPE, _SHOULD, _RESULT) \
	{ ++n; \
	std::cout << #_RESULT " = " #_SHOULD << " ... "; \
	_TYPE should = _SHOULD; \
	_TYPE result = _RESULT; \
	if( should != result ) { \
	std::cout << "FAIL (is " << _RESULT << " )" << std::endl; ++e; \
	} else {std::cout << "OK" << std::endl; } \
}
#else // MAKE_TEST
#define UNITTEST_EQUALS( _TYPE, _SHOULD, _RESULT)
#endif // MAKE_TEST


/**
 * Test if two floats have (approximatly) the same value
 */
#ifdef MAKE_TEST
#define UNITTEST_FLOAT_EQUALS(  _SHOULD, _RESULT) \
	{	++n; \
		std::cout << #_RESULT " = " #_SHOULD << " ... "; \
		float should = _SHOULD; \
		float result = _RESULT; \
		if( fabs( result - should )  > 0.001f ) { \
			std::cout << "FAIL (is " << result << " )"<< std::endl; ++e; \
		} else { \
			std::cout << "OK" << std::endl; \
		} \
	}
#else // MAKE_TEST
#define UNITTEST_FLOAT_EQUALS( _SHOULD, _RESULT )
#endif // MAKE_TEST

/**
 * Test if two vector3 have approxly the same value
 */
#ifdef MAKE_TEST
#define UNITTEST_VECTOR3_EQUALS(  _SHOULD, _RESULT) \
	{	++n; \
		std::cout << #_RESULT " = " #_SHOULD << " ... "; \
		Vector3 should = _SHOULD; \
		Vector3 result = _RESULT; \
		float diff = (should-result).length(); \
		if( fabs(diff)  > 0.001f ) { \
			std::cout << "FAIL (is " << result.getX() << "," << result.getY() << "," << result.getZ() << " )"<< std::endl; ++e; \
		} else { \
			std::cout << "OK" << std::endl; \
		} \
	}
#else // MAKE_TEST
#define UNITTEST_FLOAT_EQUALS( _SHOULD, _RESULT )
#endif // MAKE_TEST

/**
 * Test if two btVector3 have approxly the same value
 *
 *
 */
#ifdef MAKE_TEST
#define UNITTEST_BTVECTOR3_EQUALS(  _SHOULD, _RESULT) \
	{	++n; \
		std::cout << #_RESULT " = " #_SHOULD << " ... "; \
		btVector3 should = _SHOULD; \
		btVector3 result = _RESULT; \
		float diff = (should-result).length(); \
		if( fabs(diff)  > 0.001f ) { \
			std::cout << "FAIL (is " << result.getX() << "," << result.getY() << "," << result.getZ() << " )"<< std::endl; ++e; \
		} else { \
			std::cout << "OK" << std::endl; \
		} \
	}
#else // MAKE_TEST
#define UNITTEST_FLOAT_EQUALS( _SHOULD, _RESULT )
#endif // MAKE_TEST

/**
 * Test if two booleans have approxly the same value
 * 
 *
 */
#ifdef MAKE_TEST
#define UNITTEST_BOOL_EQUALS( _SHOULD, _RESULT) \
	{ ++n; \
	std::cout << #_RESULT " = " #_SHOULD << " ... "; \
	bool should = _SHOULD; \
	bool result = _RESULT; \
	if( should != result ) { \
	std::cout << "FAIL (is " << (result ? "true" : "false") << " )" << std::endl; ++e; \
	} else {std::cout << "OK" << std::endl; } \
}
#else // MAKE_TEST
#define UNITTEST_BOOL_EQUALS( _SHOULD, _RESULT )
#endif // MAKE_TEST


#define PRE_TESTING() int n=0, e=0;
#define POST_TESTING() \
	if( e==0 ) { \
		std::cout << "Passed all " << n << " tests" << std::endl;  \
		return 0; \
	} \
	std::cout << "Failed " << e << " of " << n << " tests" << std::endl;  \
	return 1; 

#ifdef MAKE_TEST

//#define BEGIN_TESTING() int main() { PRE_TESTING()
//#define END_TESTING() POST_TESTING() }

#define BEGIN_TESTING() int main() { int n=0, e=0; 
#define END_TESTING() \
	if( e==0 ) { \
		std::cout << "Passed all " << n << " tests" << std::endl;  \
		return 0; \
	} \
	std::cout << "Failed " << e << " of " << n << " tests" << std::endl;  \
	return 1;  \
} 

#define TEST_BLOCK_BEGIN() int main() { int n=0, e=0; 
#define TEST_BLOCK_END() \
	if( e==0 ) { \
		std::cout << "Passed all " << n << " tests" << std::endl;  \
		return 0; \
	} \
	std::cout << "Failed " << e << " of " << n << " tests" << std::endl;  \
	return 1;  \
} 
#define RUN_TEST(X) X(n,e);

#else // MAKE_TEST
#define BEGIN_TESTING()
#define END_TESTING()
#define TEST_BLOCK_BEGIN()
#define TEST_BLOCK_END()
#endif // MAKE_TEST


/**
 * Defines a set of tests
 *
 * USAGE:
 *
 * TESTSET(testsetHello)
 * {
 *   int a=3, b=4;
 *   UNITTEST_BOOL_EQUALS( true, myfun(a,b) );
 *   UNITTEST_BOOL_EQUALS( fasel, myfun(b,a) );
 * }
 * BEGIN_TESTING()
 *   RUN_TESTSET(hestsetHello)
 * END_TESTING()
 */
#ifdef MAKE_TEST
#define TESTSET( _NAME ) static void _ ## _NAME(int &n, int &e); \
	static void _NAME( int &n, int &e ) { \
		std::cout << "TESTSET: " << #_NAME << std::endl; \
		_ ## _NAME(n,e); } \
	static void _ ## _NAME(int &n, int &e)
#define RUN_TESTSET( _NAME ) _NAME(n,e);
#else // MAKE_TEST
#define TESTSET( _NAME ) 
#define RUN_TESTSET( _NAME )
#endif // MAKE_TEST


#endif //__TESTING_H__


